#include <modules\fileTerrainRescaleModule.h>
#include <base\global.h>
#include <io\pngstream.h>
#include <model.h>

#include "Poco\DirectoryIterator.h"
#include <Poco\File.h>
#include <Poco\Path.h>

#include <iostream>
#include <fstream>
#include <sstream>
#include <cmath>

using namespace std;

using Poco::DirectoryIterator;
using Poco::File;
using Poco::Path;

fileTerrainRescaleModule::fileTerrainRescaleModule(vec2i _tile_res,
                           vec2i _from,
                           vec2i _to,
                           vec2i _levels_interval, 
                           int _level0_offset, 
                           int _start_level) : dataModule() {
  tile_res = _tile_res;
  from = _from;
  to = _to;
  levels_interval = _levels_interval;
  level0_offset = _level0_offset;
  start_level = _start_level;
}

string itos(int value) {
  stringstream str;
  str << value;
  return str.str();
}

bool
fileTerrainRescaleModule::post(model * _model) {

  Poco::Path dst_dir(_model->getDataStorageDir());
  dst_dir.pushDirectory(_model->getModelName());

  Poco::File ofile(Poco::Path(dst_dir.absolute(), _model->getModelName() + ".def"));

  // check/create directories for all levels
  dst_dir = _model->getDataStorageDir();
  dst_dir.pushDirectory(_model->getModelName());
  dst_dir.pushDirectory("global_profile");
  dst_dir.pushDirectory(TERRAIN_DIR_BASE_NAME);
  Poco::Path source_dir(dst_dir);

  for (int level = start_level; level < levels_interval[1]; level++) {
    
    source_dir.pushDirectory(itos(level + level0_offset));
    dst_dir.pushDirectory(itos(level + level0_offset + 1));
    
    vec2i nfrom           = from / (int) pow(2.0, level);
    vec2i nto             =   to / (int) pow(2.0, level);

//    int offset_x = (nfrom[0] % 2);
    for (int col = nfrom[0]; col <= nto[0]; col++) {
      
      int col_offset     = (col) / 1024;
      int col_index      = (col) % 1024;
      int dst_col_offset = (col / 2) / 1024;
      int dst_col_index  = (col / 2) % 1024;

      source_dir.pushDirectory(itos(col_offset));
      source_dir.pushDirectory(itos(col_index));

      dst_dir.pushDirectory(itos((dst_col_offset)));
      dst_dir.pushDirectory(itos((dst_col_index)));

      iri_iter = pbins.find(col / 2);
      if (iri_iter == pbins.end()) {
        pbins[col / 2];
        iri_iter = pbins.find(col / 2);
      }
      
//      int offset_y = (nfrom[1] % 2);
      for (int row = nfrom[1]; row <= nto[1]; row++) {
        
        int row_offset = (row) / 1024;
        int row_index  = (row) % 1024;
        int dst_row_offset = (row / 2) / 1024;
        int dst_row_index  = (row / 2) % 1024;

        source_dir.pushDirectory(itos(row_offset));

        dst_dir.pushDirectory(itos((row / 2) / 1024));
        Poco::File dst_file_dir(dst_dir);
        dst_file_dir.createDirectories();
        
        iir_iter = iri_iter->second.find(row / 2);
        if (iir_iter == iri_iter->second.end()) {
          iri_iter->second[row / 2] = new pointsBin(vec2i(col / 2, row / 2), tile_res);
          iir_iter = iri_iter->second.find(row / 2);
        }

        // read the png and lazy create coarser one
        FILE *fin;
        pngstream pngs;
        unsigned short **data = new unsigned short *[tile_res[1]];
        Poco::File ifile(Poco::Path(source_dir.absolute(), itos(row_index) + ".png"));
        if (fopen_s(&fin, ifile.path().c_str(), "rb") == 0) {
          pngs.initializeInput(fin, false);
      
          int y = 0;
          while(pngs.hasNext()) {
            data[y] = (unsigned short *) pngs.readLine();
            if (y % 2 == 0) {
              for (int x = 0; x != tile_res[0]; x++) {
                if (x % 2 == 0) {
                  if (iir_iter->second->addHeight((col % 2) * (tile_res[0] / 2) + (x / 2),
                                                  (row % 2) * (tile_res[1] / 2) + (y / 2),
                                                  data[y][x])) {
                    Poco::File ofile(Poco::Path(dst_dir.absolute(), itos((row / 2) % 1024) + ".png"));
                    iir_iter->second->save(ofile.path(), 1.0);
                    delete iir_iter->second;
                    iri_iter->second.erase(iir_iter);
                  }
                }  
              }
              std::cout << std::endl;
            }
            delete [] data[y];
            y++;
          }
          delete [] data;
          pngs.finishInput();
          fclose(fin);
        }
        
        source_dir.popDirectory();

        dst_dir.popDirectory();
      }
      source_dir.popDirectory();
      source_dir.popDirectory();

      dst_dir.popDirectory();
      dst_dir.popDirectory();
    }
    source_dir.popDirectory();
    dst_dir.popDirectory();
  }

  return true;
}